package com.wwdx.controller.rest;

import com.wwdx.controller.base.BaseJdOrderController;
import com.wwdx.model.WwdxCdKeyModel;
import com.wwdx.model.WwdxJdorderModel;
import com.wwdx.model.WwdxThemeModel;
import com.wwdx.model.WwdxVipProductModel;
import com.wwdx.model.dto.BasePayDTO;
import com.wwdx.utils.AesUtil;
import com.wwdx.utils.ConstantHolder;
import com.wwdx.utils.HttpClientUtils;
import com.wwdx.utils.jackson.JsonUtils;
import com.wwdx.utils.math.BigDecimalUtils;
import org.joda.time.DateTime;
import org.springframework.retry.RecoveryCallback;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.Map;
import java.util.SortedMap;

/**
 * @author liguoliang
 * @date 2018/5/25 21:54
 */
@RestController
@RequestMapping("/jdorder")
@ApiIgnore
public class JdOrderController extends BaseJdOrderController{

    /**
     * 京东订单提取卡密
     */
    @RequestMapping("/beginDistill")
    public BasePayDTO.JdPayDTO jdorderrechange(BasePayDTO.JdPayDTO dto) {
        logger.info("京东订单提取卡密:{}",dto);
        Long costPrice = dto.getCostPrice();
        Integer type = dto.getType(),quantity = dto.getQuantity();
        DateTime dateTime = new DateTime();
        //京东订单ID | 产品ID | 接口版本 | 签名类型 | 签名 | 清算时间 | 访问时间
        String jdOrderNo = dto.getJdOrderNo(), wareNo = dto.getWareNo(),
                version = dto.getVersion(),signType = dto.getSignType(),
                sign = dto.getSign(),finTime = dto.getFinTime(),timestamp = dateTime.toString("yyyyMMddHHmmss");
        SortedMap<String, Object> sortedMap = super.getSortedMap(dto.getTimestamp(),version,jdOrderNo);
        sortedMap.put("type",type);
        sortedMap.put("finTime",finTime);
        sortedMap.put("notifyUrl",dto.getNotifyUrl());
        sortedMap.put("quantity",quantity);
        sortedMap.put("wareNo",wareNo);
        sortedMap.put("costPrice",costPrice);
        String errorCode = "";
        //验证签名
        if (!sign.equalsIgnoreCase(super.jdMd5Sign(sortedMap))){
            errorCode = BasePayDTO.JdOrderState.JDI_00002.name();
            logger.info("\n京东订单提取卡密错误信息:{}", BasePayDTO.JdOrderState.JDI_00002.getMsg());
            return getFResult(errorCode,jdOrderNo,null,sign,signType,timestamp,version);
        }
        Long productId = Long.valueOf(wareNo);
        //验证产品
        WwdxThemeModel wwdxThemeModel = wwdxThemeService.getByThemeId(productId);
        WwdxVipProductModel wwdxVipProductModel = wwdxVipProductService.getByProductId(productId);
        //产品价格
        BigDecimal d;
        //产品类型
        Integer productType;
        if (wwdxThemeModel != null){
            d = wwdxThemeModel.getPrice();
            productType = 1;
        }else if (wwdxVipProductModel != null){
            d = wwdxVipProductModel.getPrice();
            productType = 7;
        }else {
            errorCode = BasePayDTO.JdOrderState.JDI_00003.name();
            logger.info("\n京东订单提取卡密错误信息:{}", BasePayDTO.JdOrderState.JDI_00003.getMsg());
            return getFResult(errorCode,jdOrderNo,null,sign,signType,timestamp,version);
        }
        //验证产品价格
        Long price = BigDecimalUtils.calculate(d).multiply(100).getBigDecimal().longValue();
        if (!costPrice.equals(price)){
            errorCode = BasePayDTO.JdOrderState.JDI_00005.name();
            logger.info("\n京东订单提取卡密错误信息:{}", BasePayDTO.JdOrderState.JDI_00005.getMsg());
            return getFResult(errorCode,jdOrderNo,price,sign,signType,timestamp,version);
        }
        //商户订单号 | 卡密
        String agentOrderNo,cardInfo;
        //已经支付成功
        Integer status = 1;
        WwdxJdorderModel wwdxJdorderModel = wwdxJdorderService.getByJdOrderId(jdOrderNo);
        if (wwdxJdorderModel == null){
            agentOrderNo = super.makeOrderNum();
            StringBuilder sb = new StringBuilder(),sb2 = new StringBuilder();
            //格式：12345_输入卡号即可兑换_卡号永久有效
            final String cardPwd = "输入卡号即可兑换";
            final String cardTime = "卡号永久有效";
            for (int i = 0;i < quantity;i++){
                String card = super.getStringRandom(6);
                sb.append(card).append("_").append(cardPwd).append("_").append(cardTime).append("|");
                //加密前卡号
                sb2.append(card).append(",");
                //生成兑换码
                WwdxCdKeyModel wwdxCdKeyModel = WwdxCdKeyModel.builder()
                        .cdkey(card).product_id(Long.valueOf(dto.getWareNo())).type(productType).gmt_created(dateTime.toDate()).status(0).build();
                wwdxCdKeyService.save(wwdxCdKeyModel);
            }
            //加密后卡号
            cardInfo = AesUtil.encryptStrWithAes(sb.substring(0, sb.length() - 1), ConstantHolder.Constant.JDENCODE_RULES);
            WwdxJdorderModel model = WwdxJdorderModel.builder()
                    .id(agentOrderNo).costPrice(costPrice).card(sb2.substring(0, sb2.length() - 1)).finTime(finTime).jdOrderNo(jdOrderNo).quantity(quantity)
                    .cardInfo(cardInfo).wareNo(wareNo).gmtCreated(dateTime.toDate()).build();
            wwdxJdorderService.save(model);
        }else {
            agentOrderNo = wwdxJdorderModel.getId();
            cardInfo = wwdxJdorderModel.getCardInfo();
        }
        sortedMap = super.getSortedMap(timestamp, version,jdOrderNo);
        sortedMap.put("isSuccess","T");
        sortedMap.put("errorCode",errorCode);
        sortedMap.put("agentOrderNo",agentOrderNo);
        dto.setCardInfo(cardInfo);
        dto.setAgentOrderNo(agentOrderNo);
        dto.setStatus(status);
        taskExecutor.execute(()-> jdordercallback(dto));
        return getTResult(jdOrderNo,agentOrderNo,super.jdMd5Sign(sortedMap),signType,timestamp,version);
    }

    /**
     * 京东订单回调
     */
    private void jdordercallback(BasePayDTO.JdPayDTO dto) {
        logger.info("京东订单回调:{}",dto);
        String agentid = ConstantHolder.Constant.AGENTID ,
                busstype = ConstantHolder.Constant.BUSSTYPE,timestamp = new DateTime().toString("yyyyMMddHHmmss");
        SortedMap<String, Object> sortedMap = super.getSortedMap(timestamp, dto.getVersion(), dto.getJdOrderNo());
        sortedMap.put("agentId", agentid);
        sortedMap.put("bussType", busstype);
        sortedMap.put("agentOrderNo", dto.getAgentOrderNo());
        sortedMap.put("status", dto.getStatus());
        sortedMap.put("time", timestamp);
        sortedMap.put("quantity", dto.getQuantity());
        sortedMap.put("cardInfo", dto.getCardInfo());
        dto.setSign(super.jdMd5Sign(sortedMap));
        dto.setAgentId(agentid);
        dto.setBussType(busstype);
        dto.setTime(timestamp);
        dto.setTimestamp(timestamp);
        //构建重试模板实例
        RetryTemplate retryTemplate = new RetryTemplate();
        //设置重试策略，主要设置重试次数
        SimpleRetryPolicy policy = new SimpleRetryPolicy(4, Collections.singletonMap(Exception.class, true));
        //设置重试回退操作策略，主要设置重试间隔时间
        FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
        //间隔1分钟
        fixedBackOffPolicy.setBackOffPeriod(60000L);
        retryTemplate.setRetryPolicy(policy);
        retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
        //通过RetryCallback 重试回调实例包装正常逻辑逻辑，第一次执行和重试执行执行的都是这段逻辑
        final RetryCallback<Object, Exception> retryCallback = (RetryContext context)-> {
            //RetryContext 重试操作上下文约定，统一spring-try包装
            boolean result = this.retry(dto);
            if(!result){
                //这个点特别注意，重试的根源通过Exception返回
                throw new RuntimeException();
            }
            return true;
        };
        //通过RecoveryCallback 重试流程正常结束或者达到重试上限后的退出恢复操作实例
        final RecoveryCallback<Object> recoveryCallback = (RetryContext context)->null;
        try {
            //由retryTemplate 执行execute方法开始逻辑执行
            retryTemplate.execute(retryCallback, recoveryCallback);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private boolean retry(BasePayDTO.JdPayDTO dto){
        String json = HttpClientUtils.post(dto.getNotifyUrl(), dto);
        logger.info("\n京东订单回调结果:{}", json);
        Map<String, Object> map = JsonUtils.json2Map(json);
        if (CollectionUtils.isEmpty(map)){
            //重试
            return false;
        }else {
            String isSuccess = map.get("isSuccess").toString();
            //返回F重试
            return "T".equals(isSuccess);
        }
    }

    /**
     * 京东订单查询
     */
    @RequestMapping("/findDistill")
    public BasePayDTO.JdPayDTO jdordersearch(BasePayDTO.JdPayDTO dto){
        logger.info("京东订单查询:{}",dto);
        //京东订单ID | 接口版本 | 签名类型 | 签名 | 访问时间
        String jdOrderNo = dto.getJdOrderNo(), version = dto.getVersion(),
                signType = dto.getSignType(), sign = dto.getSign(),timestamp = new DateTime().toString("yyyyMMddHHmmss");
        SortedMap<String, Object> sortedMap = super.getSortedMap(dto.getTimestamp(),version,jdOrderNo);
        String errorCode = "";
        //验证签名
        if (!sign.equalsIgnoreCase(super.jdMd5Sign(sortedMap))){
            errorCode = BasePayDTO.JdOrderState.JDI_00002.name();
            logger.info("\n京东订单查询错误信息:{}", BasePayDTO.JdOrderState.JDI_00002.getMsg());
            return getFResult(errorCode,jdOrderNo,null,sign,signType,timestamp,version);
        }
        //验证产品
        WwdxJdorderModel wwdxJdorderModel = wwdxJdorderService.getByJdOrderId(jdOrderNo);
        if (wwdxJdorderModel == null){
            errorCode = BasePayDTO.JdOrderState.JDI_00007.name();
            logger.info("\n京东订单查询错误信息:{}", BasePayDTO.JdOrderState.JDI_00007.getMsg());
            return getFResult(errorCode,null,null,sign,signType,timestamp,version);
        }
        String agentOrderNo = wwdxJdorderModel.getId(),cardInfo = wwdxJdorderModel.getCardInfo();
        //quantity 购买状态 status 支付成功状态
        Integer quantity = wwdxJdorderModel.getQuantity(),status = 1;
        sortedMap = super.getSortedMap(timestamp, version,jdOrderNo);
        sortedMap.put("isSuccess","T");
        sortedMap.put("errorCode",errorCode);
        sortedMap.put("agentOrderNo",agentOrderNo);
        sortedMap.put("status",status);
        sortedMap.put("time",timestamp);
        sortedMap.put("quantity",quantity);
        sortedMap.put("cardInfo",cardInfo);
        return BasePayDTO.JdPayDTO.builder()
                .isSuccess("T").errorCode(errorCode).agentOrderNo(agentOrderNo).jdOrderNo(jdOrderNo)
                .status(status).quantity(quantity).cardInfo(cardInfo)
                .time(timestamp).sign(super.jdMd5Sign(sortedMap)).signType(signType).timestamp(timestamp)
                .version(version).build();
    }
}